/*
 * ExplicaDetailEntityView.java
 *
 * $Id: ExplicaDetailEntityView.java,v 1.11 2009-10-27 10:09:06 mario Exp $
 */
package org.ceteca.explica.client.gui;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.apache.log4j.Logger;
import org.ceteca.explica.client.ClientContext;
import org.ceteca.explica.client.gui.common.CommonClient;
import org.ceteca.explica.core.ExplicaException;
import org.ceteca.explica.core.InterfaceExplica;
import org.ceteca.explica.core.common.BaseVO;
import org.ceteca.explica.core.common.MultiSelectionSubentityOT;
import org.ceteca.explica.core.common.RegistryOT;
import org.ceteca.explica.core.installer.EntityLauncher;
import org.ceteca.explica.core.installer.EntityOT;
import org.ceteca.explica.core.installer.FieldOT;
import org.ceteca.explica.core.installer.SubentityOT;
import org.ceteca.explica.core.util.OperationResult;
import org.ceteca.explica.core.util.ResultMessage;
import org.ceteca.javaglade.Gui;
import org.ceteca.javaglade.InterfaceGladeGtk;
import org.ceteca.javaglade.JavaGladeException;
import org.ceteca.javaglade.handlers.GenericHandler;
import org.ceteca.javaglade.toolkit.swt.SwtWidget;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.ToolItem;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.swt.widgets.TreeItem;

/**
 * Helper class that implements the Explica entity GUI. 
 * It completes the glade file specification to add extra features.
 * It also implements the event handlers for the Explica entity buttons.
 * <br/>
 * Responsibilities:
 * <ul>
 * 	<li>Definition and inicialization of the Explica entity GUI. </li>
 *  <li>Event management for the Explica entity widgets.</li>
 * </ul>
 * <br/>
 * @author Mario García García <mario@imagos.es>
 * Copyright (c) 2008 Fundación Centro Tecnolóxico da Carne
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * <br/>
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * <br/>
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
public class ExplicaDetailEntityView extends ExplicaEntityView {
	/** Data of the subentity */
	private MultiSelectionSubentityOT subentityData;
//	private SubentityOT subentityData;
	
	/** Name of the subentity tree as it will be embedded into the master entity panel. */
	private String rootName;
	
	/** 
	 * Subentity multiselection (Detail entity) constructor of the ExplicaDetailEntityView class.
	 * @param parentGui Gui, instance of the parent GUI where the new GUI will be appended.
	 * @param parentWidget SwtWidget, master entity widget where the detail view will be embedded.
	 * @param Logger logger, instance of the logger used for reporting.
	 * @param subentityData SubentityOT, data of the subentity that will be presented.
	 * @param entityLauncher EntityLauncher, instance of the entity launcher that will handle the view.
	 * @param rootName String, name of the root widget that will be embedded into the
	 * master entity edition panel.
	 */
	public ExplicaDetailEntityView(Gui parentGui, SwtWidget parentWidget, Logger logger, MultiSelectionSubentityOT subentityData, EntityLauncher entityLauncher, String rootName) {
		super("");
		this.logger = logger;
		this.entityData = subentityData.getSubentityData();
		this.subentityData = subentityData;
		this.parentGui = parentGui;
		this.parentWidget = parentWidget;
		this.entityLauncher = entityLauncher;
		if (subentityData != null && subentityData.getSubentityData().getKey() != null && subentityData.getSubentityData().getKey().length() > 0)
			this.entityGuiName = InterfaceExplica.EXPLICA_ENTITY_GLADE_NAME + "_" + subentityData.getSubentityData().getKey();
		this.parentPanel = (Composite)parentWidget.getWidget();
		this.rootName = rootName;
	}

	/**
	 * Gets the subentity data.
	 * @return SubentityOT, subentity data.
	 */
	public SubentityOT getSubentityData() {
		return subentityData;
	}

	/**
	 * Initializes the Explica Entity Viewer engine and builds
	 * the entity panel. Searches automatically for the glade interface 
	 * file with the module GUI configuration.
	 */
	public void buildEntityView() {
		this.logger.info("Building entity content panel");
		this.logger.info("Parent GUI = " + this.parentGui);
		this.logger.info("Parent Widget = " + this.parentWidget);

		// Build the parent composite that will hold the entity view
		Composite entityPanel = (Composite)ExplicaGUIBuilder.getInstance().getToolkit().
			emptyPanel(this.parentPanel, InterfaceExplica.EXPLICA_ENTITY_PANEL_NAME + "_" + this.entityData.getName());
		entityPanel.setLayout(new FillLayout());
//		entityPanel.setBackground(ExplicaGUIBuilder.getInstance().getColor(SWT.COLOR_YELLOW));
		
		this.logger.info("Entity panel = " + entityPanel);
		this.parentGui.addWidget(InterfaceExplica.EXPLICA_ENTITY_PANEL_NAME + "_" + this.entityData.getName(), 
				entityPanel, this.parentWidget.getWidgetName());
		this.viewPanel = this.parentGui.getSwtWidget(InterfaceExplica.EXPLICA_ENTITY_PANEL_NAME + "_" + this.entityData.getName());
		
		this.logger.info("Widget añadido");
		
		try {
			this.gui = ExplicaGUIBuilder.getInstance().buildGUI(
					this.entityGuiName, 
					InterfaceExplica.EXPLICA_DETAIL_ENTITY_GLADE_PATH, 
					this.parentGui, 
					InterfaceExplica.EXPLICA_ENTITY_CONTENTS_PANEL_NAME,
					entityPanel,
					InterfaceExplica.EXPLICA_ENTITY_PANEL_NAME + "_" + this.entityData.getName(),
					ClientContext.getInstance().getResourceDir());
			
			this.logger.debug("GUI construida! " + this.gui);
		
			// Rename the entity table
//			Widget tree = this.gui.getWidget(InterfaceExplica.EXPLICA_ENTITY_TREE_NAME);
			this.gui.renameWidget(rootName, InterfaceExplica.EXPLICA_ENTITY_TREE_NAME);
	
			// Connect the entity tree selection listener
			this.logger.debug("Connecting entity tree change selection event to its handler...");
			this.connectEntityTreeSelectionListener();
			
			// Connect the entity toolbar buttons to their handlers.
			this.logger.debug("Connecting entity toolbar buttons to its handlers...");
			this.connectToolbarButtons();
	
			// Fill the search in combo with the searchable fields for the entity
			// and the entity table with the fields of the columns' headers.
			this.logger.debug("Filling entity search in combo...");
			this.fillEntityFields();
	
			// Fill the tree viewer with the existing registries of the entity.
			this.fillEntityTable();
			
			// Distribute the columns
//			this.distributeColumns(parentPanel.computeSize(SWT.DEFAULT, SWT.DEFAULT).x - 10);
			
			this.parentPanel.layout(true);
	
			this.logger.info("Entity panel succesfully built!");
			
			this.logger.debug("GUI built: " + this.entityGuiName + " [" + this.parentGui.getGuiName() + "]");
			ExplicaGUIBuilder.getInstance().printGUIs(this.logger);
		}
		catch (JavaGladeException ex) {
			this.gui = null;
			this.logger.error("Error building the entity detail view! " + ex.getLocalizedMessage());
		}
	}
	
	/**
	 * Fills the entity view with the selected data. 
	 */
/*	public void showEntityView() {
		this.logger.info("Showing entity contents");

		// Fill the tree viewer with the existing registries of the entity.
		this.fillEntityTable();
		
		// Distribute the columns
		this.distributeColumns(parentPanel.computeSize(SWT.DEFAULT, SWT.DEFAULT).x - 10);
		
		this.parentPanel.layout(true);
	}
*/	
	/**
	 * Connects the entity tree to their correspondent selection event
	 * handler.
	 */
/*	private void connectEntityTreeSelectionListener() {
		// Get the entity table widget
		SwtWidget treeWidget = this.getEntityTree();
		Tree entityTree = (Tree)treeWidget.getWidget();
		// Connect the select signal to the table
		ExplicaGUIBuilder.getInstance().connectSignal(InterfaceGladeGtk.GTK_SIGNAL_TYPE_SELECTCURSORROW, entityTree, 
				InterfaceExplica.EXPLICA_ENTITY_SELECTED_HANDLER, this);
		
		// Connect the double click signal to the table
		ExplicaGUIBuilder.getInstance().connectSignal(InterfaceGladeGtk.GTK_SIGNAL_TYPE_DOUBLECLICKED, entityTree, 
				InterfaceExplica.EXPLICA_ENTITY_DOUBLECLICKED_HANDLER, this);
	}
*/
	@Override
	protected void connectToolbarButtons() {
		super.connectToolbarButtons();
		
		// Get the toolitem for selecting a new entity
		ToolItem toolItemSel = (ToolItem)this.gui.getWidget(InterfaceExplica.EXPLICA_ENTITY_TOOLITEM_SELECT_NAME);
		// Connect the signal to the button
		ExplicaGUIBuilder.getInstance().connectSignal(InterfaceGladeGtk.GTK_SIGNAL_TYPE_CLICKED, toolItemSel, 
				InterfaceExplica.EXPLICA_ENTITY_SELECT_BUTTON_CLICKED_HANDLER, this);
		this.logger.debug("Select entity toolbar button connected!");
	}

	/**
	 * Fills the search in combo with the searchable fields defined
	 * for the entity.
	 */
	protected void fillEntityFields() {
		// Get the entity table widget
		Tree entityTree = this.getEntityTreeWidget();
		entityTree.setHeaderVisible(true);

		// Adjust the entity tree to fit with the parent panel's layout
		GridData gridData = new GridData();
		gridData.horizontalAlignment = SWT.FILL;
		gridData.grabExcessHorizontalSpace = true;
		gridData.verticalAlignment = SWT.FILL;
		gridData.grabExcessVerticalSpace = true;
		entityTree.setLayoutData(gridData);
		
		this.logger.debug("Entity tree found: " + entityTree);
		
		// Add the identifier field as the first column. This column will be invisible.
		if (this.entityData != null) {
			this.logger.debug("Adding identifier field: " + this.entityData.getIdField());
			TreeColumn column = new TreeColumn(entityTree, SWT.LEFT);
			column.setText(this.entityData.getIdField());
			column.setWidth(0);
			column.setResizable(false);
			column.setMoveable(false);
		}
		
		// Add the fields to the search in combo and the entity table fields column headers.
		if (this.entityData != null && this.entityData.getLFields() != null && this.entityData.getLFields().size() > 0) {
			// The column width will be automatically adjusted. The same width will be
			// assigned to each column up to the tree total width.
			int columnWidth = (parentPanel.getParent().getClientArea().width - 15) / this.getVisibleFieldsCount();
			
			this.logger.debug("Adding fields: " + this.entityData.getLFields().size() + " (" + columnWidth + " px)");

			for (FieldOT field : this.entityData.getLFields()) {
				this.logger.debug("Adding field: " + field.getName() + " - " + field.isSearchable() + " [" + field.isVisible() + "]");
				
				// Add the field to the entity table column headers.
				if (field.isVisible()) {
					TreeColumn column = new TreeColumn(entityTree, SWT.LEFT);
					column.setText(field.getName());
					column.setWidth(columnWidth);
				}
			} // for each entity field
		} // if exists any entity field
		
		this.logger.info("Entity tree created: " + entityTree.getColumnCount() + " columns     " + entityTree.getColumns());
		this.logger.info("Entity tree created: " + entityTree.getItemCount() + " items     " + entityTree.getItems());
	}
	
	/**
	 * Fills the entity tree viewer with the entity data.
	 */
	public void fillEntityTable() {
		if (this.entityLauncher != null) {
			ArrayList<RegistryOT> lRegistries = null;
			// If the entity is a detail of a master entity --> Show the multiselection entity view panel
			ArrayList<BaseVO> lSubentities = this.subentityData.getParentEntity().querySubentities(this.subentityData);
			this.entityLauncher.setRegistries(lSubentities);
			lRegistries = this.entityLauncher.formatRegistries(lSubentities);
			
			this.logger.debug("FILLING THE ENTITY VIEW'S TABLE: " + lRegistries.size());
			for (RegistryOT reg: lRegistries) {
				this.logger.debug(reg.getId() + " ... " + reg.toString());
			}
			this.fillEntityTable(lRegistries);
		}
	}
	
	/**
	 * Handler for the entity add button click event.
	 * Calls the correspondent entity launcher method for adding a new entity.
	 * @param e Event, entity add button clicked event data.
	 */
	public void on_entityAddButton_clicked(Event e) {
		this.logger.debug("Pressed Add button: " + this.entityLauncher + ", " + this.subentityData.getParentEntity() + " [" + this.subentityData.getParentFieldId() + "]");

		if (this.getSubentityData() == null)
			fireExceptionAndExit("Error. Select button clicked with null subentity data");
		if (!(this.getSubentityData() instanceof MultiSelectionSubentityOT))
			fireExceptionAndExit("Internal error. Program stopped");
		verifyEntityLauncher();

		((CommonClient) entityLauncher).addEntity();
	}
	
	/**
	 * Handler for the entity delete button click event.
	 * Calls the correspondent entity launcher method for deleting an entity.
	 * @param e Event, entity delete button clicked event data.
	 */
/*	public void on_entityDelButton_clicked(Event e) {
		if (this.entityLauncher != null) {
			// Get the entity table widget
			SwtWidget treeWidget = this.getEntityTree();
			Tree entityTree = (Tree)treeWidget.getWidget();
			this.logger.debug("Entity tree found: " + entityTree);
			
			try {
				// Get the parent entity launcher from which the selection window was requested
				EntityLauncher parentEntityLauncher = this.subentityData.getParentEntity();
				
				// Call the parentEntity launcher deselectSubentity() method for
				// updating the selecting subentity in the parent's data.
				parentEntityLauncher.deselectSubentity(this.subentityData.getParentFieldId(), this.entityLauncher.getSelectedEntity());
				this.logger.info("Entity registry successfully deleted!" + this.entityLauncher.getSelectedId());
			} // try
			catch (Exception ex) {
				this.logger.error("Error deleting entity registry!", ex);
			} // catch exception
			
			// Relayout the parent panel to refresh the view
			this.parentPanel.layout(true);
		}		
	}
*/
	
	/**
	 * Handler for the entity edit button click event.
	 * Calls the correspondent entity launcher method for editing an entity.
	 * @param e Event, entity edit button clicked event data.
	 */
/*	public void on_entityEditButton_clicked(Event e) {
		this.logger.debug("Edit button clicked: " + this.parentGui.getGuiName() + "\\" + this.entityGuiName);
		
		if (this.entityLauncher != null) {
			this.entityLauncher.editEntity();
		}
	}
*/	
	/**
	 * Handler for the entity view button click event.
	 * Calls the correspondent entity launcher method for viewing an entity.
	 * @param e Event, entity view button clicked event data.
	 */
/*	public void on_entityViewButton_clicked(Event e) {
		this.logger.debug("View button clicked: " + this.parentGui.getGuiName() + "\\" + this.entityGuiName);
		
		if (this.entityLauncher != null) {
			this.entityLauncher.viewEntity();
		}
	}
*/	
	/**
	 * Handler for the entity select button click event.
	 * Calls the correspondent entity launcher method for selecting a new entity.
	 * @param e Event, entity select button clicked event data.
	 */
	public void on_entitySelectButton_clicked(Event e) {
		this.logger.debug("Select button clicked: " + this.parentGui.getGuiName() + "\\" + this.entityGuiName);
		
		if (this.entityLauncher != null && this.entityLauncher instanceof CommonClient) {
			((CommonClient)this.entityLauncher).addExistingSubentity(this.subentityData);
		}
	}
	
/*	public void on_entity_selected(Event e) {
		this.logger.info("Selecting a new item from the entity tree...");
		// Get the entity table widget
		SwtWidget treeWidget = this.getEntityTree();
		Tree entityTree = (Tree)treeWidget.getWidget();
		
		// Get the selected table item (selected entity)
		try {
			Long selectedItem = null;
			TreeItem[] selItems = entityTree.getSelection();
			if (selItems != null && selItems.length > 0) {
				selectedItem = new Long(selItems[0].getText(0));
			} // for each selected item
			
			
			this.logger.info("Entity selected: " + selectedItem);
			this.entityLauncher.selectEntity(selectedItem);
		} // try
		catch (Exception ex) {
			ex.printStackTrace();
		} // catch exception
	}
*/	
/*	public void on_entity_doubleclicked(Event e) {
		System.out.println("¡¡¡¡¡¡ DOUBLE CLICK !!!!!!");
		this.logger.info("Editing an item from the entity tree...");
		if (this.entityLauncher != null) {
			this.entityLauncher.editEntity();
		}
	}
*/
	
/*	public Composite getEntityPanel() {
		return (Composite)this.gui.getWidget(InterfaceExplica.EXPLICA_ENTITY_PANEL_NAME);
	}
*/
	
	public SwtWidget getEntityTree() {
		this.logger.debug("?????????????????????????????");
		this.gui.printWidgets(this.logger);
		this.logger.debug("Getting entity tree: " + this.rootName + " --> " + this.gui.getSwtWidget(this.rootName));
		return this.gui.getSwtWidget(this.rootName);
	}
	
	public Collection getRegistries() {
		List<BaseVO> result = new ArrayList<BaseVO>();
		SwtWidget treeWidget = this.getEntityTree();
		Tree entityTree = (Tree)treeWidget.getWidget();
		
		if (entityTree != null) {
			for (int i = 0; i<entityTree.getItemCount(); i++) {
				System.out.println("Getting registry: " + entityTree.getItem(i).getText() + " - " + entityTree.getItem(i).getText(0));
				Long id = new Long(entityTree.getItem(i).getText());
				BaseVO reg = this.entityLauncher.getRegistry(id.longValue());
				System.out.println("Registry got: " + id.longValue() + " --> " + reg);
				result.add(this.entityLauncher.getRegistry(new Long(entityTree.getItem(i).getText()).longValue()));
			}
		}
		
		return result;
	}
	
	public void setRegistries(Collection registries) {
		if (this.entityLauncher != null)
			if (entityLauncher instanceof CommonClient)
				((CommonClient) entityLauncher).setRegistries(registries);
		this.updateView();
	}
	
	public void fireExceptionAndExit(String msg) {
		ResultMessage result = new ResultMessage(OperationResult.RESULT_ERROR,
				new Exception(msg));
		try {
			throw new ExplicaException(result);
		} catch (ExplicaException e) {

			e.printStackTrace();
			System.exit(-1);
		}
	}
	
	/**
	 * Returns tag Id assigned to CVS source file.
	 */
	public static String getRevision() {
		return "$Id: ExplicaDetailEntityView.java,v 1.11 2009-10-27 10:09:06 mario Exp $";
	}
}